package alkaid.eis.sys.controller;

import static org.springframework.util.StringUtils.hasText;

import java.util.Collections;
import java.util.List;
import java.util.Map;

import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

import alkaid.eis.sys.entity.Area;
import alkaid.eis.sys.entity.AreaComparator;
import alkaid.eis.sys.entity.AreaType;
import alkaid.eis.sys.repository.AreaRepository;
import alkaid.eis.sys.service.AreaService;
import alkaid.eis.sys.service.AreaSpecifications;
import lombok.RequiredArgsConstructor;

/**
 * 地区接口
 * 
 * @author Lucky Yang
 * @since 0.0.1
 */
@RestController
@RequestMapping("/areas")
@RequiredArgsConstructor
public class AreaController {
    private final AreaRepository areaRepository;
    private final AreaService areaService;

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public Long create(@RequestParam(name = "parentCode", required = false) String parentCode,
            @RequestBody AreaDto areaDto) {
        Area entity = areaService.save(parentCode, AreaMapper.INST.toEntity(areaDto));
        return entity.getId();
    }

    @PutMapping("/{id}")
    public Long update(@PathVariable("id") Long id, @RequestBody AreaDto areaDto) {
        Area entity = areaService.update(id, AreaMapper.INST.toEntity(areaDto));
        return entity.getId();
    }

    @DeleteMapping("/{id}")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void delete(@PathVariable("id") Long id) {
        areaService.delete(id);
    }

    @GetMapping("/all-full-name")
    public Map<String, String> getAllFullName() {
        return areaService.findFullName();
    }

    @GetMapping("/top")
    public List<AreaDto> getTop() {
        List<Area> entities = areaRepository.findByPcodeIsNull();
        Collections.sort(entities, AreaComparator.CODE);
        return AreaMapper.INST.toDto(entities);
    }

    @GetMapping("/{id}/children")
    public List<AreaDto> getChildren(@PathVariable("id") Long id) {
        Area parent = areaService.findById(id);
        List<Area> entities = areaRepository.findChildByPcode(parent.getCode());
        Collections.sort(entities, AreaComparator.CODE);
        return AreaMapper.INST.toDto(entities);
    }

    @GetMapping
    public List<AreaDto> get(@RequestParam(name = "type", required = false) AreaType type,
            @RequestParam(name = "name", required = false) String name,
            @RequestParam(name = "code", required = false) String code) {
        Specification<Area> where = AreaSpecifications.empty();
        if (type != null) {
            where = where.and(AreaSpecifications.typeEqual(type));
        }
        if (hasText(name)) {
            where = where.and(AreaSpecifications.nameLike(name));
        }
        if (hasText(code)) {
            where = where.and(AreaSpecifications.codeLike(code));
        }
        List<Area> entities = areaRepository.findAll(where);
        return AreaMapper.INST.toDto(entities);
    }

    @GetMapping("/{id}")
    public AreaDto getById(@PathVariable("id") Long id) {
        Area entity = areaService.findById(id);
        return AreaMapper.INST.toDto(entity);
    }

    @GetMapping("/code/{code}")
    public AreaDto getByCode(@PathVariable("code") String code) {
        Area entity = areaService.findByCode(code);
        return AreaMapper.INST.toDto(entity);
    }
}
